#ifndef TOKEN_H
#define TOKEN_H
#include <string>
#include <vector>
#include "global.h"
#include "stl-util.h"
#include "conversion.h"

namespace tinyscript{
namespace internal{
class Scanner;
// Token is a lexer symbol used to represents the specific type of a recognized
// syntax. A token is tightly binded to a stream, it has a stream context related
// member data which is the start and end of this Token. Therefore a token is typically
// a triple value (TokenName,StartIndex,EndIndex)
class Token {
public:
    enum {
        // 1) Mathematic Operator
        TT_ADD, //1
        TT_SUB, //2
        TT_MUL, //3
        TT_DIV, //4
        TT_MOD, // %5
        // 2) Logic Operator
        TT_AND, // &&6
        TT_OR , // ||7
        TT_NOT, // !8
        TT_LT , // <9
        TT_GT , // >10
        TT_LET, // <=11
        TT_GET, // >=12
        TT_EQ , // ==13
        TT_NEQ, // ~=14
		TT_DOT, // .15
		TT_DOLLAR , // $16
		TT_POUND, // #17
		TT_AT , //@18
		TT_AMP , // &19
        // 3) Other Operator
        TT_RLBRACKET , // }20
        TT_LLBRACKET , // {21
        TT_RMBRACKET , // ]22
        TT_LMBRACKET , // [23
        TT_RSBRACKET , // )24
        TT_LSBRACKET , // (25
        TT_ASSIGN , // =26
        TT_END , // ; 27
        TT_COMMA , // , 28
        // 4) Variable
        TT_SYMBOL  , //29
        TT_STRING ,//30
        TT_INT ,//31
        TT_FLOAT ,//32
        TT_TRUE ,//33
        TT_FALSE,//34
        TT_NULL ,//35
        // 5) Keyword
		TT_VAR ,//36
		TT_GLOBAL,//37
        TT_FUNCTION , // function 38
        TT_IF ,// if 39
        TT_ELSE ,// else 40
        TT_ELSEIF , // elseif 41
        TT_FOR  , // for 42
        TT_FOREACH, //43
        TT_WHILE, // while 44
        TT_DO , // do 45
        TT_PASS , //pass 46
        TT_CONTINUE , // continue; 47
        TT_BREAK , // break
		TT_RETURN, // return
        // 6) EOF
        TT_EOF , // end of the file
        TT_WHITESPACE , // whitespace
        TT_COMMENTS , // comments
        // 7) Reserved
        TT_ERROR,

        TOKEN_SIZE
    };

public:
    Token( int t , size_t is , size_t ie ) :
        token_(t),
        index_start_(is),
        index_end_(ie){}

    Token():
        token_(TT_ERROR),
        index_start_(),
        index_end_(0){}

	explicit Token( int tk ) :
		token_(tk),
		index_start_(0),
		index_end_(0){}

    size_t index_start() const {
        return index_start_;
    }
	void set_index_start( size_t s ) {
		index_start_ = s;
	}
    size_t index_end() const {
        return index_end_;
    }
	void set_index_end( size_t s ) {
		index_end_ = s;
	}
    int token() const {
        return token_;
    }
	void set_token( int i ) {
		token_ = i;
	}

	std::string GetTokenRawString( const std::vector<char_t>& buffer ) const {
		return tinyscript::util::FromString(buffer,index_start_,index_end_);
	}
	
	template< typename T > 
	T GetTokenValue( const std::vector<char_t>& buffer ) const;

	// Get the string value corresponding to the TOKEN
	template<> 
	std::string Token::GetTokenValue<std::string>( const std::vector<char_t>& buffer )const  {
		assert( token_ == Token::TT_STRING );
		std::string ret;
		ret.reserve( index_end_ - index_start_ );
		for( size_t i = index_start_ ; i < index_end_ ; ++i ) {
			const char_t c = buffer[i];
			if( c == '\\' ) {
				continue;
			}
			ret.push_back(static_cast<char>(c));
		}
		return ret;
	}

	template<>
	int Token::GetTokenValue<int>( const std::vector<char_t>& buffer ) const {
		assert( token_ == Token::TT_INT );
		return StringToInt(buffer,index_start_,index_end_);
	}

	template<>
	double Token::GetTokenValue<double>( const std::vector<char_t>& buffer ) const {
		assert( token_ == Token::TT_FLOAT );
		return StringToDouble(buffer,index_start_,index_end_);
	}

	template<>
	bool Token::GetTokenValue<bool>( const std::vector<char_t>& buffer ) const {
        USE(buffer);
		assert(token_ == Token::TT_TRUE || token_ == Token::TT_FALSE );
		return token_ == Token::TT_TRUE ? true : false;
	}

	std::string GetSymbolName( const std::vector<char_t>& buffer ) const {
		assert(token_ == Token::TT_SYMBOL);
		return GetTokenRawString(buffer);
	}

public:

    static const char* GetTokenName( const Token& t ) {
		return GetTokenName(t.token());
	}
	static const char* GetTokenName( int t );

private:
    friend class Scanner;
    int token_;
    size_t index_start_ , index_end_;
};

}
}// namespace sscript

#endif // TOKEN_H
